/******************************************
 *Author:周正阳
 *Function:简单和中等的AI算法
 *Created Date:2013.05.21
 *Last Modified:2013.05.28
 ******************************************/


#include "data.h"
#include "win.h"
#include "forbidden.h"
#include "ai.h"

# define SPA 0
# define FIR 1
# define LAST 2
/* 空位置设为0 先手的位置设为1 ，后手的位置设为2 */

void AI(int *p,int *q)           /* 简单难度电脑下子 *p *q返回下子坐标 */
{
    int i,j,k,max=0,I,J;        /* I J为下点坐标 i j为循环变量 k为中间变量 max为价值最大值*/
    for(j=0;j<15;j++)
        for(i=0;i<15;i++)
            if(ChessBoard[j][i]==SPA){      /* 历遍棋盘，遇到空点则计算价值，取最大价值点下子。 */
                k=value(i,j);
                if(!IsHumanFirst && (ChessBoard[j][i]=1) && isban(j,i) && DoForbidden) {
                    k=-9999999999;
                }							/* 禁手的判断，如果禁手则附最小值 */
                ChessBoard[j][i]=0;
                if(k>=max) { I=i; J=j; max=k; }
            }
            *p=I; *q=J;
}
void AI1(int *p,int *q)           /* 电脑下子 *p *q返回下子坐标 */
{
    int i,j,k,max=-9999999999,I,J;        /*  I J为下点坐标 i j为循环变量 k为中间变量 max为价值最大值 */
    for(j=0;j<15;j++)
        for(i=0;i<15;i++)
            if(ChessBoard[j][i]==SPA){/* 历遍棋盘，遇到空点则计算价值，取最大价值点下子。 */
                k=value1(i,j);
                if(!IsHumanFirst && (ChessBoard[j][i]=1) && isban(j,i) && DoForbidden) {
                    k=-9999999999;
                }					 /* 禁手的判断，如果禁手则附最小值 */
                ChessBoard[j][i]=0;
                if(k>max) { I=i; J=j; max=k; }
            }
            *p=I; *q=J;
}
int value(int p,int q) /* 计算空点p q的价值 以va返回 */
{
    int n=1,va=0;	   /* n为循环变量、移位函数变量 va为价值 */
    int qx1,qx2,Dqx1,Dqx2,X1,Y1,Z1,X2,Y2,Z2,tem;
    int val[2][4][4]={40,400,3000,10000,6,10,600,10000,20,120,200,0,6,10,500,0,30,300,2500,5000,2,8,300,8000,26,160,0,0,4,20,300,0};
    /* 数组a中储存己方和对方共32种棋型的值  己方0对方1    活0冲1空活2空冲3    子数0-3（0表示1个子，3表示4个子） */
    /* 每个棋型的价值存在三维数组val中，方便调用 */
    /* 棋型号注解:  己活000-003 己冲010-013 对活100-103 对冲110-113 己空活020-023 己空冲030-033 对空活120-123 对空冲130-133 空-1 边界冲-2 边界空冲-3*/
    while(n!=5){                        /*如果n为5，则棋盘8个方向均已遍历结束，循环跳出，返回价值 */
        qx1=qixing(n,p,q); n+=4;			/* k1,k2为2个反方向的棋型编号 */
        qx2=qixing(n,p,q); n-=3;
        if(qx1>qx2) { tem=qx1; qx1=qx2; qx2=tem; }  /* 使编号小的为k1,大的为k2 */
        Dqx1=qx1; Dqx2=qx2;       /* K1 K2储存k1 k2的编号 */
        Z1=qx1%10; Z2=qx2%10; qx1/=10; qx2/=10; Y1=qx1%10; Y2=qx2%10; qx1/=10; qx2/=10; X1=qx1%10; X2=qx2%10;
        /* X分别表示 己方0对方1    Y分别表示 活0冲1空活2空冲3    Z分别表示子数0-3（0表示1个子，3表示4个子） */
        if(Dqx1==-1)
        {
            if(Dqx2<0) { va+=0; continue; }			/* 空棋型 */
            else va+=val[X2][Y2][Z2]+5; continue;		/* 其他棋型 */
        };
        if(Dqx1==-2)
        {
            if(Dqx2<0) { va+=0; continue; }         /* 边界冲棋型 */
            else va+=val[X2][Y2][Z2]/2; continue;     /* 其他棋型 */
        };
        if(Dqx1==-3)
        {
            if(Dqx2<0) { va+=0; continue; }			/* 边界空冲棋型 */
            else va+=val[X2][Y2][Z2]/3; continue;     /* 其他棋型 */
        };
        if(((Dqx1>-1&&Dqx1<4)&&((Dqx2>-1&&Dqx2<4)||(Dqx2>9&&Dqx2<14)))||((Dqx1>99&&Dqx1<104)&&((Dqx2>99&&Dqx2<104)||(Dqx2>109&&Dqx2<114)))){
            /* 己活己活                             己活己冲              对活对活                                     对活对冲 */
            if(Z1+Z2>=2) { va+=val[X2][Y2][3]; continue; } /* 四子相连的棋型 */
            else { va+=val[X2][Y2][Z1+Z2+1]; continue; }   /* 四子以下的棋型 */
        }
        if(((Dqx1>9&&Dqx1<14)&&(Dqx2>9&&Dqx2<14))||((Dqx1>109&&Dqx1<114)&&(Dqx2>109&&Dqx2<114))){
            /* 己冲己冲                             对冲对冲 */
            if(Z1+Z2>=2) { va+=10000; continue; }          /* 四子相连的棋型 */
            else { va+=0; continue; }                      /* 四子以下的棋型 */
        }
        if(((Dqx1>-1&&Dqx1<4)&&((Dqx2>99&&Dqx2<104)||(Dqx2>109&&Dqx2<114)))||((Dqx1>9&&Dqx1<14)&&((Dqx2>99&&Dqx2<104)||(Dqx2>109&&Dqx2<114)))){
            /* 己活对活                               己活对冲                 己冲对活                                  己冲对冲 */
            if(Z1==3||Z2==3) { va+=10000; continue; }
            else { va+=val[X2][Y2][Z2]+val[X1][Y1][Z1]/4; continue; }
        }
        else  { va+=val[X1][Y1][Z1]+val[X2][Y2][Z2]; continue;  }    /* 其他棋型的赋值 */
    }
    return va;
}
int qixing(int n,int p,int q)            /* 返回空点p q在n方向上的棋型号 n为1-8方向 从右顺时针开始数 */
{
    int qx,num=0;  /* 棋型号注解:  己活000-003 己冲010-013 对活100-103 对冲110-113 己空活020-023 己空冲030-033 对空活120-123 对空冲130-133 空-1 边界冲-2 边界空冲-3*/
    if (!IsHumanFirst)			/* 电脑先手，则电脑所选子为FIR，即FIR为己方子 */
    {
        yiwei(n,&p,&q);			/* 先进行移位 */
        if(p<0||p>14||q<0||q>14) qx=-2;                                      /* 边界冲棋型 */
        switch(ChessBoard[q][p]){
        case FIR:{                                                       /* 若为己方棋子 */
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; }				 /* 己方冲棋型 */
            while(ChessBoard[q][p]==FIR)					/* 继续为己方棋子时进行判断 */
            {
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; }       /* 己方活棋型 */
            }
            if(ChessBoard[q][p]==SPA) qx=num-1;                    /* 己方活棋型 */
            else qx=num+9;                                         /* 己方冲棋型 */
                 }break;
        case LAST:{                                             /* 若为对方棋子 */
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; }     /* 对方冲棋型 */
            while(ChessBoard[q][p]==LAST)                  /* 继续为对方棋子时进行判断 */
            {
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; }
            }
            if(ChessBoard[q][p]==SPA) qx=num+99;                    /* 对方活棋型 */
            else qx=num+109;                                        /* 对方冲棋型 */
                  }break;
        case SPA:{                                               /* 若为空 */
            yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=-3; return qx; }         /* 边界空冲棋型 */
            switch(ChessBoard[q][p]){
            case FIR:{                                           /* 若为己方棋子 */
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; }	 /* 己方空冲棋型*/
                while(ChessBoard[q][p]==FIR)
                {
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; } }  /* 己方空冲棋型*/
                if(ChessBoard[q][p]==SPA) qx=num+19;                 /* 己方空活棋型 */
                else qx=num+29;                                      /* 己方空冲棋型 */
                     }break;
            case LAST:{                                           /* 若为对方棋子 */
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; }   /* 对方空冲棋型 */
                while(ChessBoard[q][p]==LAST)
                { num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; } } /* 对方空冲棋型 */
                if(ChessBoard[q][p]==SPA) qx=num+119;                /* 对方空活棋型 */
                else qx=num+129;                                     /* 对方空冲棋型 */
                      }break;
            case SPA: qx=-1; break;                                /* 空棋型 */
            }
                 }break;
        }
        return qx;											      /*返回棋型值*/
    }
    else              /* 若为电脑后手 */
    {
        yiwei(n,&p,&q);
        if(p<0||p>14||q<0||q>14) qx=-2;                                      /* 边界冲棋型 */
        switch(ChessBoard[q][p]){
        case LAST:{                                               /* 若为己方棋子 */
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; }		  /* 己方冲棋型 */
            while(ChessBoard[q][p]==LAST)
            {
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; } }       /* 己方冲棋型 */
            if(ChessBoard[q][p]==SPA) qx=num-1;                      /* 己方活棋型 */
            else qx=num+9;                                           /* 己方冲棋型 */
                  }break;
        case FIR:{                                                /* 若为对方棋子 */
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; }       /* 对方冲棋型 */
            while(ChessBoard[q][p]==FIR)
            {
                num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; } }     /* 对方冲棋型 */
            if(ChessBoard[q][p]==SPA) qx=num+99;                     /* 对方活棋型 */
            else qx=num+109;                                         /* 对方冲棋型 */
                 }break;
        case SPA:{                                                /*若为空位置*/
            yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=-3; return qx; }         /* 边界空冲棋型 */
            switch(ChessBoard[q][p]){
            case LAST:{
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; }	 /* 己方空冲棋型*/
                while(ChessBoard[q][p]==LAST)
                { num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; } } /* 己方空冲棋型*/
                if(ChessBoard[q][p]==SPA) qx=num+19;                /* 己方空活棋型 */
                else qx=num+29;                                     /* 己方空冲棋型 */
                      }break;
            case FIR:{
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; }  /* 对方空冲棋型 */
                while(ChessBoard[q][p]==FIR)
                { num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; } }/* 对方空冲棋型 */
                if(ChessBoard[q][p]==SPA) qx=num+119;               /* 对方空活棋型 */
                else qx=num+129;                                    /* 对方空冲棋型 */
                     }break;
            case SPA: qx=-1; break;                               /* 空棋型 */
                    }
                }break;
        }
        return qx;												 /* 返回棋型值 */
    }
}
void yiwei(int n,int *p,int *q)        /* 在n方向上对坐标 i j 移位 n为1-8方向 从右顺时针开始数 */
{
    switch(n){
    case 1: *p+=1; break;
    case 2: *p+=1; *q+=1; break;
    case 3: *q+=1; break;
    case 4: *p-=1; *q+=1; break;
    case 5: *p-=1; break;
    case 6: *p-=1; *q-=1; break;
    case 7: *q-=1; break;
    case 8: *p+=1; *q-=1; break;
    }
}
int valuer(int p,int q) /* 计算人下子时空点p q的价值 以va返回 算法与value相同，仅仅修改了qixing函数的返回情况*/
{
    int n=1,va=0;
    int qx1,qx2,Dqx1,Dqx2,X1,Y1,Z1,X2,Y2,Z2,tem;
    int val[2][4][4]={40,400,3000,10000,6,10,600,10000,20,120,200,0,6,10,500,0,30,300,2500,5000,2,8,300,8000,26,160,0,0,4,20,300,0};
    while(n!=5){
        qx1=qixing1(n,p,q); n+=4;
        qx2=qixing1(n,p,q); n-=3;
        if(qx1>qx2) { tem=qx1; qx1=qx2; qx2=tem; }
        Dqx1=qx1; Dqx2=qx2;
        Z1=qx1%10; Z2=qx2%10; qx1/=10; qx2/=10; Y1=qx1%10; Y2=qx2%10; qx1/=10; qx2/=10; X1=qx1%10; X2=qx2%10;
        if(Dqx1==-1)
        {
            if(Dqx2<0) { va+=0; continue; }
            else va+=val[X2][Y2][Z2]+5; continue;
        };
        if(Dqx1==-2)
        {
            if(Dqx2<0) { va+=0; continue; }
            else va+=val[X2][Y2][Z2]/2; continue;
        };
        if(Dqx1==-3)
        {
            if(Dqx2<0) { va+=0; continue; }
            else va+=val[X2][Y2][Z2]/3; continue;
        };
        if(((Dqx1>-1&&Dqx1<4)&&((Dqx2>-1&&Dqx2<4)||(Dqx2>9&&Dqx2<14)))||((Dqx1>99&&Dqx1<104)&&((Dqx2>99&&Dqx2<104)||(Dqx2>109&&Dqx2<114)))){
            if(Z1+Z2>=2) { va+=val[X2][Y2][3]; continue; }
            else { va+=val[X2][Y2][Z1+Z2+1]; continue; }
        }
        if(((Dqx1>9&&Dqx1<14)&&(Dqx2>9&&Dqx2<14))||((Dqx1>109&&Dqx1<114)&&(Dqx2>109&&Dqx2<114))){
            if(Z1+Z2>=2) { va+=10000; continue; }
            else { va+=0; continue; }
        }
        if(((Dqx1>-1&&Dqx1<4)&&((Dqx2>99&&Dqx2<104)||(Dqx2>109&&Dqx2<114)))||((Dqx1>9&&Dqx1<14)&&((Dqx2>99&&Dqx2<104)||(Dqx2>109&&Dqx2<114)))){
            if(Z1==3||Z2==3) { va+=10000; continue; }
            else { va+=val[X2][Y2][Z2]+val[X1][Y1][Z1]/4; continue; }
        }
        else  { va+=val[X1][Y1][Z1]+val[X2][Y2][Z2]; continue;  }
    }
    return va;
}
int qixing1(int n,int p,int q)            /* 计算人价值的qixing函数，算法与qixing函数相同，修改了己方识别 */
{
    int qx,num=0;
    if (IsHumanFirst)
    {
        yiwei(n,&p,&q);
        if(p<0||p>14||q<0||q>14) qx=-2;
        switch(ChessBoard[q][p]){
        case FIR:{
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; }
            while(ChessBoard[q][p]==FIR) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; } }
            if(ChessBoard[q][p]==SPA) qx=num-1;
            else qx=num+9;
                 }break;
        case LAST:{
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; }
            while(ChessBoard[q][p]==LAST) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; } }
            if(ChessBoard[q][p]==SPA) qx=num+99;
            else qx=num+109;
                  }break;
        case SPA:{
            yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=-3; return qx; }
            switch(ChessBoard[q][p]){
            case FIR:{
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; }
                while(ChessBoard[q][p]==FIR) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; } }
                if(ChessBoard[q][p]==SPA) qx=num+19;
                else qx=num+29;
                     }break;
            case LAST:{
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; }
                while(ChessBoard[q][p]==LAST) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; } }
                if(ChessBoard[q][p]==SPA) qx=num+119;
                else qx=num+129;
                      }break;
            case SPA: qx=-1; break;
            }
                 }break;
        }
        return qx;
    }
    else
    {
        yiwei(n,&p,&q);
        if(p<0||p>14||q<0||q>14) qx=-2;
        switch(ChessBoard[q][p]){
        case LAST:{
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; }
            while(ChessBoard[q][p]==LAST) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+9; return qx; } }
            if(ChessBoard[q][p]==SPA) qx=num-1;
            else qx=num+9;
                  }break;
        case FIR:{
            num++; yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; }
            while(ChessBoard[q][p]==FIR) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+109; return qx; } }
            if(ChessBoard[q][p]==SPA) qx=num+99;
            else qx=num+109;
                 }break;
        case SPA:{
            yiwei(n,&p,&q);
            if(p<0||p>14||q<0||q>14) { qx=-3; return qx; }
            switch(ChessBoard[q][p]){
            case LAST:{
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; }
                while(ChessBoard[q][p]==LAST) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+29; return qx; } }
                if(ChessBoard[q][p]==SPA) qx=num+19;
                else qx=num+29;
                      }break;
            case FIR:{
                num++; yiwei(n,&p,&q);
                if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; }
                while(ChessBoard[q][p]==FIR) { num++; yiwei(n,&p,&q); if(p<0||p>14||q<0||q>14) { qx=num+129; return qx; } }
                if(ChessBoard[q][p]==SPA) qx=num+119;
                else qx=num+129;
                     }break;
            case SPA: qx=-1; break;
            }
                 }break;
        }
        return qx;
    }
}
int value1(int p,int q)			  /* 中等电脑价值算法函数 预算一步 */
{
    int chess[15][15];			  /* 预判时，棋盘上每点价值 */
    int i,j;					  /* 循环变量 */
    int max=0,tem=value(p,q);	  /* 预判时的最大值，p q点 电脑价值 */
    ifempty(p,q);				  /* 现在这点上下子，进行下一步预算 */
    for(j=0;j<15;j++)
        for(i=0;i<15;i++)
            chess[j][i]=0;		  /* 数组重置 */
    for(j=0;j<15;j++)
        for(i=0;i<15;i++)
        {chess[j][i]=valuer(j,i); /* 对于人的价值 */
         if(chess[j][i]>=max)
         max=chess[j][i];}
    ChessBoard[q][p]=SPA;		  /* 撤销修改 */
    return tem+max/2;			  /* 返回这点预算一步之后的综合价值 */
}
void ifempty(int j,int i)			/* 预判时的下子函数 由先后手判断电脑所持字颜色，并下子 */
{
    if (IsHumanFirst)				/* 电脑后手 */
        ChessBoard[i][j]=LAST;
    else                            /* 电脑先手 */
        ChessBoard[i][j]=FIR;
}
